Technote DV 05 | June 1985 |
DrvQEl = RECORD qLink: QElemPtr; {next queue entry} qType: INTEGER; {queue type} dQDrive: INTEGER; {drive number} dQRefNum: INTEGER; {driver reference number} dQFSID: INTEGER; {file-system identifier} dQDrvSz: INTEGER; {number of logical blocks on drive} dQDrvSz2: INTEGER; {additional field to handle large drive size} END;
Note that dQDrvSz2 is only used if qType is 1. In this case, dQDrvSz2 contains the high-order word of the size, and dQDrvSz contains the low-order word.
Inside Macintosh also mentions four bytes of flags that preced each drive queue entry. How are these flags accessed? The flags begin 4 bytes before the address pointed to by the DrvQElPtr. In assembly language, accessing this isn't a problem:
MOVE.L -4(A0),D0 ;A0 = DrvQElPtr; get drive queue flags
If you're using Pascal, it's a little more complicated. You can get to the flags with this routine:
FUNCTION DriveFlags(aDQEPtr: DrvQElPtr): LONGINT; VAR flagsPtr : ^LONGINT; {we'll point at drive queue flags with this} BEGIN {subtract 4 from the DrvQElPtr, and get the LONGINT there} flagsPtr := POINTER(ORD4(aDQEPtr) - 4); DriveFlags := flagsPtr^; END;
From MPW C, you can use:
long DriveFlags(aDQEPtr) DrvQElPtr aDQEPtr; { /* DriveFlags */ return(*((long *)aDQEPtr - 1)); /* coerce flagsPtr to a (long *) so that subtracting 1 from it will back us up 4 bytes */ } /* DriveFlags */
To add a drive to the drive queue, assembly-language programmers can use the function defined below. It takes two parameters: the driver reference number of the driver which is to "own" this drive, and the size of the new drive in blocks. It returns the drive number created. It is vital that you not hard-code the drive number; if the user has installed other non-standard drives in the queue, the drive number you're expecting may already be taken. (Note that the example function below arbitrates to find an unused drive number, taking care of this problem for you. Also, note that this function doesn't mount the new volume; your code should take care of that, calling the Disk Initialization Package to reformat the volume if necessary).
AddMyDrive PROC EXPORT ;--------------------------------------------------------------------------- ;FUNCTION AddMyDrive(drvSize: LONGINT; drvrRef: INTEGER): INTEGER; ;--------------------------------------------------------------------------- ;Add a drive to the drive queue. Returns the new drive number, or a negative ;error code (from trying to allocate the memory for the queue element). ;--------------------------------------------------------------------------- DQESize EQU 18 ;size of a drive queue element ;We use a constant here because the number in SysEqu.a doesn't take into ;account the flags LONGINT before the element, or the size word at the end. ;--------------------------------------------------------------------------- StackFrame RECORD {link},DECR result DS.W 1 ;function result params EQU * drvSize DS.L 1 ;drive size parameter drvrRef DS.W 1 ;drive refNum parameter paramSize EQU params-* return DS.L 1 ;return address link DS.L 1 ;saved value of A6 from LINK block DS.B ioQElSize ;parameter block for call to MountVol linkSize EQU * ENDR ;--------------------------------------------------------------------------- WITH StackFrame ;use the offsets declared above LINK A6,#linkSize ;create stack frame ;search existing drive queue for an unused number LEA DrvQHdr,A0 ;get the drive queue header MOVEQ #4,D0 ;start with drive number 4 CheckDrvNum MOVE.L qHead(A0),A1 ;start with first drive CheckDrv CMP.W dqDrive(A1),D0 ;does this drive already have our number? BEQ.S NextDrvNum ;yep, bump the number and try again. CMP.L A1,qTail(A0) ;no, are we at the end of the queue? BEQ.S GotDrvNum ;if yes, our number's unique! Go use it. MOVE.L qLink(A1),A1 ;point to next queue element BRA.S CheckDrv ;go check it. NextDrvNum ;this drive number is taken, pick another ADDQ.W #1,D0 ;bump to next possible drive number BRA.S CheckDrvNum ;try the new number GotDrvNum ;we got a good number (in D0.W), set it aside MOVE.W D0,result(A6) ;return it to the user ;get room for the new DQE MOVEQ #DQESize,D0 ;size of drive queue element, adjusted _NewPtr sys ;get memory for it BEQ.S GotDQE ;no error...continue MOVE.W D0,result(A6) ;couldn't get the memory! return error BRA.S FinishUp ;and exit GotDQE ;fill out the DQE MOVE.L #$80000,(A0)+ ;flags: non-ejectable; bump past flags MOVE.W #1,qType(A0) ;qType of 1 means we do use dQDrvSz2 CLR.W dQFSID(A0) ;"local file system" MOVE.W drvSize(A6),dQDrvSz2(A0) ;high word of number of blocks MOVE.W drvSize+2(A6),dQDrvSz(A0) ;low word of number of blocks ;call AddDrive MOVE.W result(A6),D0 ;get the drive number back SWAP D0 ;put it in the high word MOVE.W drvrRef(A6),D0 ;move the driver refNum in the low word _AddDrive ;add this drive to the drive queue FinishUp UNLK A6 ;get rid of stack frame MOVE.L (SP)+,A0 ;get return address ADDQ #paramSize,SP ;get rid of parameters JMP (A0) ;back to caller ;--------------------------------------------------------------------------- ENDPROC
Further Reference: